namespace MyStorage {
  export interface IStorage {
    get(name: string): any
    set(name: string, value: any): void
    remove(name: string): void
    clear(): void
    forceClear(): void
    usageSize(): string
  }
  abstract class AbsStorage {
    protected formatSize(byte: number): string {
      if (byte < 1024 * 1024) {
        return (byte / 1024).toFixed(2) + 'KB'
      } else {
        return (byte / (1024 * 1024)).toFixed(2) + 'MB'
      }
    }
  }

  export class ls extends AbsStorage implements IStorage {
    get(name: string) {
      return localStorage.getItem(name)
    }

    set(name: string, value: any) {
      localStorage.setItem(name, value)
    }

    remove(name: string) {
      localStorage.removeItem(name)
    }

    clear() {
      for (let i = 0; i < localStorage.length; i++) {
        const key = localStorage.key(i)
        if (key !== null) {
          if (key.substring(0, 5) === 'crm_') {
            this.remove(key)
            i--
          }
        } else {

        }
      }
    }

    forceClear() {
      localStorage.clear()
    }

    usageSize(): string {
      let size = 0
      for (let i = 0; i < localStorage.length; i++) {
        const key = localStorage.key(i)
        if (key !== null && key.substring(0, 5) === 'erp3_') {
          const val = localStorage.getItem(key)
          size += key.length + (val ? val.length : 0)
        }
      }
      return this.formatSize(size)
    }
  }
}

// 已使用的key
type StorageKey =
  'v' // 版本号
  | 'productCategory' // 上传产品分类
  | 'nodeSelectHistory' // 节点编号选择历史
  | any

/**
 * 最终储存格式
 * {
 *  expireAt: 过期时间，
 *  data: 数据,
 *  version: 版本
 * }
 */
class Adapter {
  /** 数据引擎 */
  static engine = 'ls'
  /** 过期时间 */
  static expireTime = 0
  /** 前缀 */
  static prefix = 'crm_'
  static version = ''
  static getKey(name: StorageKey) {
    return this.prefix + name
  }

  static get(name: StorageKey) {
    const preName = this.getKey(name)
    let data
    // @ts-ignore
    const storageFactory: MyStorage.IStorage = new MyStorage[this.engine]()
    data = Reflect.apply(storageFactory.get, storageFactory, [preName])

    if (!data) {
      return null
    }

    data = JSON.parse(data)

    if ((data.expireAt !== 0 && new Date() > new Date(data.expireAt)) || (this.version !== '' && data.version !== this.version)) {
      this.remove(name)
      return null
    }
    return data.data
  }

  static set(name: StorageKey, value: any, expireTime: number = this.expireTime, version: string = this.version) {
    const save = {
      expireAt: expireTime === 0 ? 0 : (new Date()).getTime() + expireTime * 1000,
      version,
      data: value
    }
    const _save = JSON.stringify(save)
    // @ts-ignore
    const storageFactory: MyStorage.IStorage = new MyStorage[this.engine]()
    return Reflect.apply(storageFactory.set, storageFactory, [this.getKey(name), _save])
  }

  static remove(name: StorageKey) {
    // @ts-ignore
    const storageFactory: MyStorage.IStorage = new MyStorage[this.engine]()
    return Reflect.apply(storageFactory.remove, storageFactory, [this.getKey(name)])
  }

  static clear() {
    // @ts-ignore
    const storageFactory: MyStorage.IStorage = new MyStorage[this.engine]()
    return Reflect.apply(storageFactory.clear, storageFactory, [])
  }

  static expire(time: number) {
    this.expireTime = time
    return this
  }

  static v(version?: string) {
    if (version) {
      this.version = version
      this.set('v', version)
    } else {
      return this.get('v')
    }
  }

  static usageSize(): string {
    // @ts-ignore
    const storageFactory: MyStorage.IStorage = new MyStorage[this.engine]()
    return Reflect.apply(storageFactory.usageSize, storageFactory, [])
  }
}

export default Adapter
